package com.lanren.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.*;

public class JwtToken {

    /**
     * 私钥密码，保存在服务器，客户端是不会知道密码的，以防止被攻击
     */
    private static final String SECRET = "lanren_family";

    /**
     * 生成Token
     * <p>
     * JWT分成3部分：1.头部（header),2.载荷（payload, 类似于飞机上承载的物品)，3.签证（signature)
     * <p>
     * 加密后这3部分密文的字符位数为：
     * 1.头部（header)：36位，Base64编码
     * 2.载荷（payload)：没准，BASE64编码
     * 3.签证（signature)：43位，将header和payload拼接生成一个字符串，
     * 使用HS256算法和我们提供的密钥（secret,服务器自己提供的一个字符串），
     * 对str进行加密生成最终的JWT
     *
     * @return
     * @throws Exception
     */
    public static String createToken(String userId, String userOs) throws Exception {

        // 签发时间
        Date iatDate = new Date();
        Calendar cal=Calendar.getInstance();
        cal.add(Calendar.DATE,1);//这里改为1
        cal.set(Calendar.HOUR_OF_DAY, 22);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date time=cal.getTime();

        // 设置过期时间 - 设置签发时间5秒钟后为延迟时间，这里只是做测试，实际时间会比这个长很多
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.SECOND, 5);
        // 得到过期时间
        Date expirensDate = nowTime.getTime();

        // 组合header
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");

        String token = JWT.create() // 首先需要通过调用jwt.create()创建一个JWTCreator实例
                .withHeader(map) // header
                .withClaim("userId", userId) // payload
                .withClaim("userOs", userOs)
                .withClaim("userOs1", userOs)
                .withClaim("userOs2", userOs)
                .withClaim("userOs3", userOs)
                .withClaim("userOs4", userOs)
                .withClaim("userOs5", userOs)
                .withClaim("userOs6", userOs)
//                .withExpiresAt(expirensDate) // 设置过期时间，过期时间要大于签发时间
                .withIssuedAt(time) // 设置签发时间
                .sign(Algorithm.HMAC256(SECRET)); // 使用算法器进行加密

        return token;
    }


    /**
     * 解密Token查看其是否合法
     *
     * @param token
     * @return Claim 可以获取payload 信息
     */
    public static boolean verifyToken(String token) {
        try {
            // 校验一开始，先要把保存在服务器端的密码传入校验池
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("对Token进行了校验，并且校验通过！");
            return true;
        } catch (JWTVerificationException e) {
            e.printStackTrace();
            System.out.println("验证Token出现错误，登录认证已过期，请重新登陆");
            return false;
        } catch (Exception e) {
            System.out.println("未知错误");
            return false;
        }
    }

    /**
     * 验证一起请求（request）是否合法，包括请求时间是否超时，Token是否合法
     *
     * @param dateClient
     * @param token
     * @param interval
     * @return
     */
    public static boolean verifyRequest(Date dateClient, String token, long interval) {
        boolean flag = false;
        Date dateServer = new Date();
        if (verifyToken(token)) {
            // 如果请求从客户端到服务器的传输时间小于规定的时间差，则认为是正常请求
            if ((dateServer.getTime() - dateClient.getTime()) < interval) {
                System.out.println("Token验证成功，并且时间符合要求");
                flag = true;
            } else {
                System.out.println("Token验证成功，但请求超时");
                flag = false;
            }
        } else {
            System.out.println("Token验证失败");
            flag = false;
        }
        return flag;
    }

    /**
     * 验证Token是否合法
     *
     * @param token
     * @param userId 用户id
     * @param userOs 用户使用系统
     * @return
     */
    public static String getVerifyResult(String token, String userId, String userOs) {
        String code = null;
        if (verifyToken(token)) {
            code = "token验证通过";
        } else {

        }
        return code;
    }

    /**
     * 获取登陆用户ID
     *
     * @param token
     * @return
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取登陆用户设备系统
     *
     * @param token
     * @return
     */
    public static String getUserOs(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userOs").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取token过期时间
     *
     * @param token
     * @return
     */
    public static Date getExpiresAt(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getExpiresAt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取token创建时间
     *
     * @param token
     * @return
     */
    public static Date getIssuedAt(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getIssuedAt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }
}
